package commands;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Pattern;

import commands.Command.Commands;

/**
 * The parses loops through the file given at construction.
 * Each line is a command, and each command contains a text
 * representation of the command, as well as a variable number of arguments.
 * @author bfults (Brian Fults - 905084698)
 *
 */
public class CommandFileParser
{
    /**
     * Lines are delimited by a newline.
     */
    private static final String LINE_DELIMETER = "\n";
    /**
     * Tokens are delimited by a tab.
     */
    private static final String TOKEN_DELIMETER = "\t";
    
    Scanner lineScanner, tokenScanner;
    String currentLine;
    File commandFile;
    /**
     * Sets the instance of the command file and creates a scanner over
     * the lines.
     * @param commandFile
     * @throws FileNotFoundException
     */
    public CommandFileParser( File commandFile ) throws FileNotFoundException
    {
        this.commandFile = commandFile;
        lineScanner = new Scanner(this.commandFile );
        lineScanner.useDelimiter(LINE_DELIMETER);
        do
        {
            if (lineScanner.hasNext())
            {
                currentLine = lineScanner.next();
            }
            else
            {
                currentLine = null;
            }
        }
        while (currentLine != null && currentLine.startsWith(";"));
    }

    /**
     * Returns true if more potential commands exist.
     * @return true as long as we have more lines.
     */
    public boolean hasMoreCommands()
    {
        return currentLine != null;
    }
    
    public void close()
    {
        lineScanner.close();
    }

    /**
     * Gets the next command.  There are actually several
     * types of Commands.  This method identifies the command
     * text, as well as the argument list that may follow.
     * @return the identified Command.  May be null if we couldn't
     * identify it.
     */
    public Command nextCommand()
    {
        
        tokenScanner = new Scanner( currentLine );
        tokenScanner.useDelimiter( TOKEN_DELIMETER );

        String commandText = tokenScanner.next();
        ArrayList<String> args = new ArrayList<String>();
        while ( tokenScanner.hasNext() )
        {
            args.add(tokenScanner.next().trim());
        }
        do
        {
            if (lineScanner.hasNext())
            {
                currentLine = lineScanner.next();
            }
            else
            {
                currentLine = null;
            }
        }
        while (currentLine != null && currentLine.startsWith(";"));
        return identifyCommand( commandText, args );
    }

    /**
     * Identifies the command as one of the given types.
     * @param commandText text that should have the command
     * @param args Arguments for the given command.
     * @return
     */
    private Command identifyCommand( String commandText, List<String> args )
    {
        Command toReturn = null;
        Commands command;
        try
        {
            command = Commands.toCommand( commandText.trim() );
        }
        catch ( IllegalArgumentException e )
        {
            return null;
        }
        switch ( command )
        {
            case EXIT:
                toReturn = new ExitCommand( args );
                break;
            case IMPORT:
                toReturn = new ImportCommand(args);
                break;
            case IDENTIFY_BY_NAME:
                toReturn = new IdentifyByNameCommand(args);
                break;
            case SHOW_STATS_FOR:
                toReturn = new ShowStatsForCommand(args);
                break;
            case REMOVE:
                toReturn = new RemoveCommand(args);
                break;
            case SHOW_INDEX_FOR:
                toReturn = new ShowIndexForCommand(args);
                break;
            case IMPORT_BATTING:
                toReturn = new ImportBattingCommand(args);
                break;
            case SHOW_BATTING_DETAILS_FOR:
                toReturn = new ShowBattingDetailsCommand(args);
                break;
            case SHOW_BATTING_SUMMARY_FOR:
                toReturn = new ShowBattingSummaryCommand(args);
                break;
            case SHOW_BATTING_SUMMARY_FOR_RANGE:
                toReturn = new ShowBattingSummaryRangeCommand(args);
                break;
        }
        return toReturn;
    }
}
